/**
 * @file lv_obj_matrix.h
 *
 */

#ifndef LV_OBJ_MATRIX_H
#define LV_OBJ_MATRIX_H

#ifdef __cplusplus
extern "C" {
#endif

/*********************
 *      INCLUDES
 *********************/
#include "../../../lvgl/src/core/lv_obj.h"

#if LV_USE_OBJ_MATRIX

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**<Matrix object distance from outer frame margin */
typedef struct {
    uint16_t left;
    uint16_t right;
    uint16_t top;
    uint16_t bottom;
}lv_obj_matrix_margin_t;

typedef struct {
    uint16_t x;
    uint16_t y;
}lv_obj_matrix_cell_size_t;

/**< Create matrix unit callback function*/
typedef void (*create_cell_cb_t)(lv_obj_t *matrix, uint16_t hpos, uint16_t vpos);

/**< delete matrix unit callback function, */
typedef void (*delete_cell_cb_t)(lv_obj_t *matrix, uint16_t hpos, uint16_t vpos);

/**< Cell Container Event, when hpos or vpos is netative, then sys event*/
/**< event_code = LV_EVENT_SIZE_CHANGED: hpos= -get_hspace(matrix), vpos=-get_vspace(matrix));*/
/**< event_code = LV_EVENT_KEY: hpos = key, vpos = -1;*/
typedef void (*event_cell_cb_t)(lv_obj_t *matrix, lv_event_code_t event_code, int16_t hpos, int16_t vpos);

struct _lv_obj_matrix_info_t{/**<Matrix object distance from outer frame margin */
    create_cell_cb_t create_cell_cb;
    delete_cell_cb_t delete_cell_cb;
    event_cell_cb_t event_cell_cb;
    lv_obj_matrix_margin_t margin;
    lv_obj_matrix_cell_size_t cellsize; /**< the size of the cell container, 0:auto max size*/
    uint16_t hcount;        /**< Number of horizontal objects, 0:auto count*/
    uint16_t vcount;        /**< Number of vertical objects, 0:auto count */
    int16_t ccount;         /**< when hcount or vcount is 0, use this count（0:auto; >0:growth y-axis; <0: growth x-axis)*/
    lv_align_t align;       /**< align */
};

typedef struct _lv_obj_matrix_info_t lv_obj_matrix_info_t;

LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_obj_matrix_class;
/**********************
 * GLOBAL PROTOTYPES
 **********************/

/**
 * Create a matrix object
 * @param parent    pointer to an object, it will be the parent of the new matrix
 * @return          pointer to the created matrix
 */
lv_obj_t * lv_obj_matrix_create(lv_obj_t * parent);

/**
 * Create a matrix object
 * @param parent    pointer to a matrix
 * @param info      The initial information required to create an object matrix
 * @return          void
 */
void lv_obj_matrix_set_info(lv_obj_t * obj, const struct _lv_obj_matrix_info_t *info);

/**
 * Used to update the arrangement, called after the child control is created
 * @param obj   pointer to a matrix
 * @return      void
 */
void lv_obj_matrix_update(lv_obj_t * obj);
/**
 *  when delete_cell_cb != null, Before deleting Martinix,call to notify the deletion of user content
 * @param obj   pointer to a matrix
 * @return      void
 */
void lv_obj_matrix_del_preprocessing(lv_obj_t * obj);

/**
 * change the change count, involving the deletion and creation of cell container
 * @param obj              pointer to a matrix
 * @param hcount           Number of horizontal objects, 0:auto count
 * @param vcount           Number of vertical objects, 0:auto count
 * @param ccount           when hcount or vcount is 0, use this count（0:auto; >0:growth y-axis; <0: growth x-axis)
 * @param cellsize_x       Horizontal cell size, 0:auto max size
 * @param cellsize_y       Vertical cell size, 0:auto max size
 * @return                 void
 */
void lv_obj_matrix_set_count(lv_obj_t * obj, uint16_t hcount, uint16_t vcount, uint16_t ccount, uint16_t cellsize_x, uint16_t cellsize_y);

/**
 * change the Horizontal cell count, when hcount non-zero then valid
 * @param obj              pointer to a matrix
 * @param hcount           Horizontal cell count, need non-zero
 * @return                 void
 */
void lv_obj_matrix_set_hcount(lv_obj_t * obj, uint16_t hcount);

/**
 * change the Vertical cell count, when vcount non-zero then valid
 * @param obj              pointer to a matrix
 * @param vcount           Vertical cell count, need non-zero
 * @return                 void
 */
void lv_obj_matrix_set_vcount(lv_obj_t * obj, uint16_t vcount);

/**
 * change the cell count, when hcount or vcount is 0 then valid
 * @param obj              pointer to a matrix
 * @param ccount           need non-zero, >0:growth y-axis; <0: growth x-axis
 * @return                 void
 */
void lv_obj_matrix_set_ccount(lv_obj_t * obj, uint16_t ccount);

/**
 * change Horizontal cell size, when cellsize.x non-zero then valid
 * @param obj              pointer to a matrix
 * @param cellsize_x       Horizontal cell size,, need non-zero
 * @return                 void
 */
void lv_obj_matrix_set_cellsize_x(lv_obj_t * obj, uint16_t cellsize_x);

/**
 * change Vertical cell size, when cellsize.y non-zero then valid
 * @param obj              pointer to a matrix
 * @param cellsize_y       Vertical cell size,, need non-zero
 * @return                 void
 */
void lv_obj_matrix_set_cellsize_y(lv_obj_t * obj, uint16_t cellsize_y);

/**
 * change align
 * @param obj              pointer to a matrix
 * @param align            align mode, non automatic mode direction is valid
 * @return                 void
 */
void lv_obj_matrix_set_align(lv_obj_t * obj, lv_align_t align);
/**
 * change margin
 * @param obj              pointer to a matrix
 * @param margin           matrix margin
 * @return                 void
 */
void lv_obj_matrix_set_margin(lv_obj_t * obj, const lv_obj_matrix_margin_t *margin);

/**********************
 * GLOBAL PROTOTYPES (GETTER)
 **********************/

/**
 * get container id from a matrix
 * @param matrix   pointer to a matrix
 * @param hpos      horizontal position of matrix
 * @param vpos      vertical position of matrix
 * @return          id of the obj, -1 is invalid
 */
int16_t lv_obj_matrix_get_cell_id(lv_obj_t * obj, uint16_t hpos, uint16_t vpos);

/**
 * get container from a matrix
 * @param matrix   pointer to a matrix
 * @param hpos      horizontal position of matrix
 * @param vpos      vertical position of matrix
 * @return           pointer to the obj, NULL is invalid
 */
lv_obj_t * lv_obj_matrix_get_cell_container(lv_obj_t * obj, uint16_t hpos, uint16_t vpos);

/**
 * get Number of horizontal objects
 * @param matrix   pointer to a matrix
 * @return         Number of horizontal objects
 */
uint16_t lv_obj_matrix_get_vcount(lv_obj_t * obj);

/**
 * get Number of Vertical objects
 * @param matrix   pointer to a matrix
 * @return         Number of Vertical objects
 */
uint16_t lv_obj_matrix_get_hcount(lv_obj_t * obj);
/**
 * get the total number of matrix, when ccountvalid, it may be larger than then
 * @param matrix   pointer to a matrix
 * @return         total number of matrix
 */
uint16_t lv_obj_matrix_get_count(lv_obj_t * obj);

/**
 * get the total number of user settings
 * @param matrix   pointer to a matrix
 * @return         number of user settings
 */
uint16_t lv_obj_matrix_get_valid_count(lv_obj_t * obj);

/**
 * get the horizontal spacing between two cells
 * @param matrix   pointer to a matrix
 * @return         horizontal spacing between two cells
 */
uint32_t lv_obj_matrix_get_hspace(lv_obj_t * obj);

/**
 * get the vertical spacing between two cells
 * @param matrix   pointer to a matrix
 * @return         vertical spacing between two cells
 */
uint32_t lv_obj_matrix_get_vspace(lv_obj_t * obj);


/**********************
 *      MACROS
 **********************/

#endif /*LV_USE_OBJ_MATRIX*/

#ifdef __cplusplus
} /*extern "C"*/
#endif

#endif /*LV_OBJ_MATRIX_H*/
